package com.bwie.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.bwie.common.constants.JwtConstants;
import com.bwie.common.constants.TokenConstants;
import com.bwie.common.exception.BusinessException;
import com.bwie.common.pojo.dto.GoodsDto;
import com.bwie.common.pojo.po.AuditPo;
import com.bwie.common.pojo.po.GoodsPo;
import com.bwie.common.pojo.po.OrderPo;
import com.bwie.common.pojo.po.UserPo;
import com.bwie.common.result.Result;
import com.bwie.common.utils.StringUtils;
import com.bwie.easy.EasyPoiUtil;
import com.bwie.mapper.GoodsMapper;
import com.bwie.service.GoodsService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.hash.BloomFilter;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
@Log4j2
public class GoodsServiceImpl implements GoodsService {
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private BloomFilter<String> bloomFilter;
    @Autowired
    private RedissonClient redissonClient;
    @SneakyThrows
    @Override
    public Result getGoodsList(GoodsDto goodsDto) {
        // 获取Token并从Redis中获取UserPo对象
        String header = request.getHeader(TokenConstants.TOKEN);
        UserPo userPo = (UserPo) redisTemplate.opsForValue().get(JwtConstants.USER_KEY + header);

        // 从Redis获取roleId结果，并进行类型转换（假设Result实现了Serializable接口）
        Result<List<Integer>> roleIdResult = (Result<List<Integer>>) redisTemplate.opsForValue().get("login:role" + userPo.getUserId());
        List<Integer> roleIds = roleIdResult.getData();

        // 根据用户角色设置商品状态
        if(roleIds.contains(1)){
            goodsDto.setGoodsStatus("0");
            goodsDto.setUserId(userPo.getUserId());
        }

        // 创建缓存键名
        String goodsKey = String.format("goods:list:page:%d:size:%d", goodsDto.getPageNum(), goodsDto.getPageSize());

        // 尝试从Redis获取缓存的商品列表
        PageInfo<GoodsPo> goodsValue = (PageInfo<GoodsPo>) redisTemplate.opsForValue().get(goodsKey);
        if(goodsValue != null){
            return Result.success(goodsValue);
        }

        // 获取分布式锁
        RLock lock = redissonClient.getLock("lock:goods:list:" + goodsDto.getPageNum());
        try {
            // 尝试获取锁
            boolean locked = lock.tryLock(3, 30, TimeUnit.SECONDS);
            if (!locked) {
                return Result.error(500, "系统繁忙，请稍后再试");
            }

            // 双重检查缓存
            goodsValue = (PageInfo<GoodsPo>) redisTemplate.opsForValue().get(goodsKey);
            if (goodsValue != null) {
                return Result.success(goodsValue);
            }

            PageHelper.startPage(goodsDto.getPageNum(), goodsDto.getPageSize());

            // 如果是第一页，尝试使用特定缓存
            if(goodsDto.getPageNum() == 1 && redisTemplate.hasKey("goods:pageNum:one")) {
                goodsValue = (PageInfo<GoodsPo>) redisTemplate.opsForValue().get("goods:pageNum:one");
                return Result.success(goodsValue);
            }
            // 查询数据库获取商品列表
            List<GoodsPo> list = goodsMapper.list(goodsDto);
            PageInfo<GoodsPo> pageInfo = new PageInfo<>(list);
            // 设置缓存（过期时间）
            int expireTime = (4 * 60) + new Random().nextInt(120);
            redisTemplate.opsForValue().set(goodsKey, pageInfo, expireTime, TimeUnit.SECONDS);
            // 如果是第一页，也单独缓存一份
            if(goodsDto.getPageNum() == 1) {
                redisTemplate.opsForValue().set("goods:pageNum:one", pageInfo, expireTime, TimeUnit.SECONDS);
            }
            return Result.success(pageInfo);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("查询商品列表线程被中断", e);
            return Result.error(500, "系统繁忙，请稍后再试");
        } catch (Exception e) {
            log.error("查询商品列表异常", e);
            return Result.error(500, "系统异常，请稍后再试");
        } finally {
            // 确保只在当前线程持有锁时才释放
            if(lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    @Override
    public Result goodsAdd(GoodsDto goodsDto) {
        //判断参数
        if(ObjectUtil.isEmpty(goodsDto)){
            throw new BusinessException(Result.error("参数异常"));
        }
        if(StringUtils.isBlank(goodsDto.getGoodsName())){
            throw new BusinessException(Result.error("商品名称不能为空"));
        }
        if (bloomFilter.mightContain(goodsDto.getGoodsName())){
            throw new BusinessException(Result.error("商品已存在"));
        }
        if (goodsDto.getGoodsPrice().equals(BigDecimal.ZERO)){
            throw new BusinessException(Result.error("价格不能为0"));
        }
        //新增商品初始状态设为"待上架"
        goodsDto.setGoodsStatus("1");
        Boolean flag = redisTemplate.opsForValue().setIfAbsent("oneGoodsName", 1, 1, TimeUnit.MINUTES);
        if(flag==true){
            throw new BusinessException(Result.error("请勿多次点击"));
        }
        goodsMapper.add(goodsDto);
        bloomFilter.put(goodsDto.getGoodsName());
        return Result.success(null,"添加成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result audit(GoodsDto goodsDto) {
        goodsDto.setGoodsStatus("0");
        goodsMapper.update(goodsDto.getGoodsId(),goodsDto.getGoodsStatus());
        //审核记录表
        AuditPo auditPo = new AuditPo();
        auditPo.setAuditName(goodsDto.getGoodsName());
        String header = request.getHeader(TokenConstants.TOKEN);
        UserPo userPo = (UserPo) redisTemplate.opsForValue().get(JwtConstants.USER_KEY + header);
        auditPo.setUserId(userPo.getUserId());
        goodsMapper.addAudit(auditPo);
        return Result.success("审核完毕");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result del(GoodsDto goodsDto) {
        if (goodsDto.getGoodsStatus().equals("0")){
            throw new BusinessException(Result.error("已上架商品无法删除"));
        }
        goodsMapper.del(goodsDto.getGoodsId());
        goodsMapper.delAll(goodsDto.getGoodsId());
        return Result.success(null,"删除成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result pay(GoodsDto goodsDto) {
        if(ObjectUtil.isEmpty(goodsDto)){
            throw new BusinessException(Result.error("网络异常"));
        }
        if(goodsDto.getGoodsNum()>100){
            throw new BusinessException(Result.error("库存只有100"));
        }
        Integer goodsNum = goodsDto.getGoodsNum();
        BigDecimal num = new BigDecimal(goodsNum);
        BigDecimal multiply = goodsDto.getGoodsPrice().multiply(num);
        //订单添加
        OrderPo orderPo = new OrderPo();
        String header = request.getHeader(TokenConstants.TOKEN);
        UserPo userPo = (UserPo) redisTemplate.opsForValue().get(JwtConstants.USER_KEY + header);
        orderPo.setCreatePerson(String.valueOf(userPo.getUserId()));
        orderPo.setUpdatePerson(String.valueOf(userPo.getUserId()));
        orderPo.setOrderName(goodsDto.getGoodsName());
        orderPo.setOrderStatus(1);
        orderPo.setOrderPrice(multiply);
        goodsMapper.orderAdd(orderPo);
        return Result.success(multiply);
    }

    @Override
    public Result buy(GoodsDto goodsDto) {
        goodsDto.setGoodsStatus("0");
        goodsMapper.upd(goodsDto);
        if(goodsDto.getGoodsStatus()=="0"){
            throw new BusinessException(Result.error("已经购买过"));
        }
        return Result.success(null,"状态更改成功");
    }
    @Autowired
    private EasyPoiUtil easyPoiUtil;
    @Autowired
    private HttpServletResponse resp;
    @Override
    public void out() {
        List<GoodsPo> list = goodsMapper.list(null);
        easyPoiUtil.exportExcel(resp,list,GoodsPo.class,"导出文件");
    }

    @Override
    public void insert(MultipartFile file) {
        List<GoodsPo> list = easyPoiUtil.importFileExcel(file, GoodsPo.class);
        System.out.println(list);
        goodsMapper.insertGoods(list);
    }


}
